package com.hmdp.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.dto.Result;
import com.hmdp.entity.SeckillVoucher;
import com.hmdp.entity.VoucherOrder;
import com.hmdp.mapper.VoucherOrderMapper;
import com.hmdp.service.ISeckillVoucherService;
import com.hmdp.service.IVoucherOrderService;
import com.hmdp.service.IVoucherService;
import com.hmdp.utils.RedisIdWorker;
import com.hmdp.utils.UserHolder;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * <p>
 * 服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
public class VoucherOrderServiceImpl extends ServiceImpl<VoucherOrderMapper, VoucherOrder> implements IVoucherOrderService {

    @Autowired
    private IVoucherService voucherService;
    @Autowired
    private ISeckillVoucherService seckillVoucherService;
    @Autowired
    private RedisIdWorker redisIdWorker;
    @Autowired
    private IVoucherOrderService voucherOrderService;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Override
    public Result secKillVoucher(Long voucherId) {
/*
        //1.根据id查询优惠券信息
        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
        //2.判断是否开始
        if (LocalDateTime.now().isBefore(seckillVoucher.getCreateTime())) {
            //2.1没有开始，返回错误信息
            return Result.fail("秒杀活动暂未开始");
        }
        if(LocalDateTime.now().isAfter(seckillVoucher.getEndTime())){
            return Result.fail("秒杀活动已经结束");
        }
        //3.已经开始，查看库存
        //3.1库存不充足，返回
        if (seckillVoucher.getStock() <= 0) {
            return Result.fail("秒杀优惠券库存不足");
        }
        //3.2库存充足，扣库存
        */
/*Integer stock = seckillVoucher.getStock();
        seckillVoucher.setStock(--stock);
        seckillVoucherService.updateById(seckillVoucher);*//*

        //TODO 基于乐观锁思想解决超卖问题
        LambdaUpdateWrapper<SeckillVoucher> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.setSql("stock = stock -1 ");
        updateWrapper.eq(SeckillVoucher::getVoucherId,voucherId);
        updateWrapper.gt(SeckillVoucher::getStock,0);
        boolean success = seckillVoucherService.update(updateWrapper);
        if(!success){
            return Result.fail("秒杀优惠券库存不足");
        }
        //TODO 判断订单是否已经存在，如果存在，返回异常
        //TODO 资料是判断user_id和voucher_id是否相同，但是不同时期的voucher_id是不同的(看RedisIdWorker的逻辑)
        Long userId = UserHolder.getUser().getId();
        LambdaQueryWrapper<VoucherOrder> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(VoucherOrder::getUserId,userId);
        VoucherOrder voucherOrder = voucherOrderService.getOne(queryWrapper);
        if(ObjectUtil.isNotNull(voucherOrder)){
            return Result.fail("用户已经购买过秒杀优惠券");
        }
        //4.创建订单，返回订单id
        //4.1给订单创建用户名
        voucherOrder.setUserId(userId);
        //4.2给订单创建订单id
        long orderId = redisIdWorker.nextId("order");
        voucherOrder.setVoucherId(orderId);
        //4.3给用户创建代金券id
        voucherOrder.setVoucherId(voucherId);
        voucherOrderService.save(voucherOrder);
        return Result.ok("订单创建成功");
*/
        //1.查询订单
        SeckillVoucher seckillVoucher = seckillVoucherService.getById(voucherId);
        //2.判断秒杀是否开始
        if (seckillVoucher.getBeginTime().isAfter(LocalDateTime.now())) {
            return Result.fail("秒杀活动尚未开始");
        }
        if (seckillVoucher.getEndTime().isBefore(LocalDateTime.now())) {
            return Result.fail("秒杀活动已经结束");
        }
        //3.判断库存是否充足
        if (seckillVoucher.getStock() <= 0) {
            return Result.fail("库存不足");
        }
        Long userId = UserHolder.getUser().getId();
        //创建锁对象
//        SimpleRedisLock simpleRedisLock = new SimpleRedisLock(stringRedisTemplate, "order:" + userId);
        RLock redissonClientLock = redissonClient.getLock("lock:order:" + userId);
        //尝试获取锁
        boolean isLock = redissonClientLock.tryLock();
        if (!isLock) {
            return Result.fail("不允许重复下单");
        }
        try {
            //获取代理对象(事务)
            IVoucherOrderService proxy = (IVoucherOrderService)AopContext.currentProxy();
            return proxy.createVoucherOrder(voucherId);

        } finally {
            //释放锁
            redissonClientLock.unlock();
        }
    }
    @Transactional
    public Result createVoucherOrder(Long voucherId) {
        //1.实现一人一单
        Long userId= UserHolder.getUser().getId();

        synchronized (userId.toString().intern()) {
            /*LambdaQueryWrapper<VoucherOrder> voucherOrderQueryWrapper = new LambdaQueryWrapper<>();
            voucherOrderQueryWrapper.eq(VoucherOrder::getId, voucherId).eq(VoucherOrder::getUserId, userId);
            int count = voucherOrderService.count(voucherOrderQueryWrapper);*/
            int count = query().eq("user_id",userId).eq("voucher_id",voucherId).count();
            if (count > 0) {
                return Result.fail("用户已经购买过一次，不允许重复购买");
            }
        }
            //2.扣减库存
            boolean success = seckillVoucherService.update().setSql("stock = stock - 1")
                    .eq("voucher_id",voucherId).gt("stock",0)
                    .update();
            if(!success){
                return Result.fail("秒杀券库存不足");
            }
            //3.创建订单
            VoucherOrder voucherOrder = new VoucherOrder();
            //3.1创建订单号
            long orderId = redisIdWorker.nextId("order");
            voucherOrder.setId(orderId);
            //3.2设置用户id
            voucherOrder.setUserId(userId);
            //3.3设置代金券id
            voucherOrder.setVoucherId(voucherId);
            voucherOrderService.save(voucherOrder);
            return Result.ok("orderId");

    }
}
